using System;
using CoreTypes;
using HTMLayout;
using System.Linq;
using System.Text;
using System.Custom;
using System.Drawing;
using CustomControls;
using HtmlViewControl;
using System.Xml.Linq;
using System.Windows.Forms;
using System.ComponentModel;
using MainModule.Properties;
using System.Custom.Window;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Collections.ObjectModel;

namespace MainModule
{
   public partial class ChatControl : SessionVisualizer
   {
      #region Data

      HtmlView FHtmlView;
      IContainer components = null;
      ContextMenuStrip FMenuEmoPopup;

      bool FLiteHtml;
      bool FShowStatusEvents;
      XElement[] FHistoryCache;
      int FHistoryPageIndex = -1;
      bool FCurrentPageTrimmed = true;
      TextDataTypes FContentFilter = TextDataTypes.None;
      string FUrlStub = "<url:" + DateTime.Now.Ticks + ">";
      Collection<string> FUrlBuf = new Collection<string>();

      MessageTemplateParts FLiteMessageTemplateParts;
      MessageTemplateParts FSelectedMessageTemplateParts;
      string FStatusEventTemplate = Resources.T_StatusEvent;

      Image FSessionIcon = ResourceWrapper.GetImage("UserGreen2");
      Image FSysMessageIcon = ResourceWrapper.GetImage("RedLightning_16");
      Image FInMessageIcon = ResourceWrapper.GetImage("OdnoklPostBlue_S");
      Image FOutMessageIcon = ResourceWrapper.GetImage("OdnoklPostYellow_S");

      Element FLastImgElement;
      ServiceMessage FLastShownMessage;
      ServiceMessage FMessageToAppendTo;

      #endregion

      #region Initializers

      void InitializeComponent()
      {
         this.components = new System.ComponentModel.Container();
         System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChatControl));
         this.FMenuEmoPopup = new System.Windows.Forms.ContextMenuStrip(this.components);
         this.SuspendLayout();
         // 
         // panelStartPage
         // 
         resources.ApplyResources(this.panelStartPage, "panelStartPage");
         // 
         // panelMainPage
         // 
         resources.ApplyResources(this.panelMainPage, "panelMainPage");
         // 
         // menuEmoPopup
         // 
         this.FMenuEmoPopup.Name = "menuEmoPopup";
         resources.ApplyResources(this.FMenuEmoPopup, "menuEmoPopup");
         // 
         // ChatControl
         // 
         resources.ApplyResources(this, "$this");
         this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
         this.Name = "ChatControl";
         this.Controls.SetChildIndex(this.panelStartPage, 0);
         this.Controls.SetChildIndex(this.panelMainPage, 0);
         this.ResumeLayout(false);

      }

      public ChatControl()
      {
         // Do not remove this constructor, Visual Designer uses it.
         InitializeComponent();
      }

      public ChatControl(IBaseCommunicator communicator, IMediaSession session)
         : base(communicator)
      {
         InitializeComponent();

         Session = session;
         SessionDescription = Resources.S_Chat_session_allows_you;

         FLiteMessageTemplateParts = new MessageTemplateParts(Resources.T_MessageLite);
         FSelectedMessageTemplateParts = new MessageTemplateParts(FCommunicator.SelectedMessageTemplate);

         Settings.Default.PropertyChanged += settings_PropertyChanged;
      }

      protected override void Dispose(bool disposing)
      {
         Settings.Default.PropertyChanged -= settings_PropertyChanged;
         
         if (disposing && (components != null))
         {
            components.Dispose();
         }
         base.Dispose(disposing);
      }

      #endregion

      #region Properties

      bool LiteHtml
      {
         get
         {
            //return false;
            return FLiteHtml;
         }
         set
         {
            FLiteHtml = value;
         }
      }
      string LogStyle
      {
         get
         {
            return LiteHtml ? Resources.LogStyleText + Resources.CommonLogStyle : FCommunicator.SelectedLogStyle;
         }
      }
      MessageTemplateParts MessageTemplateParts
      {
         get
         {
            return LiteHtml ? FLiteMessageTemplateParts : FSelectedMessageTemplateParts;
            //return FSelectedMessageTemplateParts;
         }
      }

      public int HistoryPageIndex
      {
         get
         {
            return FHistoryPageIndex;
         }
         set
         {
            if (value == FHistoryPageIndex && !FCurrentPageTrimmed) return;

            ShowHistoryPage(value, true, false);
         }
      }
      public int HistoryFilesCount
      {
         get
         {
            return Session.IsPersonal ?
                   FCommunicator.EventLog.GetFilesCount(Session.Interlocutor) :
                   FCommunicator.EventLog.GetFilesCount(Session as MediaSession);
         }
      }
      public bool ShowStatusEvents
      {
         get
         {
            return FShowStatusEvents;
         }
         set
         {
            if (value == FShowStatusEvents) return;

            if (value)
            {
               FShowStatusEvents = true;

               foreach (Element el in FHtmlView.SelectElements(".status"))
               {
                  el.set_styleAttribute("visibility", "visible");
               }

               FHtmlView["log"].HtmlElement.ScrollToChild(false, false);
            }
            else
            {
               ShowHistoryPage(HistoryPageIndex, false, true);
            }
         }
      }
      public bool CurrentPageTrimmed
      {
         get
         {
            return FCurrentPageTrimmed;
         }
      }

      public override IMediaSession Session
      {
         get
         {
            return base.Session;
         }
         set
         {
            if (base.Session != null)
            {
               base.Session.ParamsChanged -= session_ParamsChanged;
               base.Session.ChatMessageReceived -= session_ChatMessageReceived;
               base.Session.PresenceNotified -= session_PresenceNotified;
               base.Session.SendChatMessageState -= session_SendMessageState;
               base.Session.SendInvitationState -= session_SendMessageState;
               base.Session.InvitationReceived -= session_InvitationReceived;
               base.Session.ParticipantsChanged -= session_ParticipantsChanged;
               base.Session.AcknowledgeReceived -= session_AcknowledgeReceived;
               base.Session.ChatMessageUpdateReceived -= session_MessageUpdateReceived;
               base.Session.InvitationReplyReceived -= session_InvitationReplyReceived;
            }

            base.Session = value;

            if (base.Session != null)
            {
               base.Session.ParamsChanged += session_ParamsChanged;
               base.Session.ChatMessageReceived += session_ChatMessageReceived;
               base.Session.PresenceNotified += session_PresenceNotified;
               base.Session.SendChatMessageState += session_SendMessageState;
               base.Session.SendInvitationState += session_SendMessageState;
               base.Session.InvitationReceived += session_InvitationReceived;
               base.Session.ParticipantsChanged += session_ParticipantsChanged;
               base.Session.AcknowledgeReceived += session_AcknowledgeReceived;
               base.Session.ChatMessageUpdateReceived += session_MessageUpdateReceived;
               base.Session.InvitationReplyReceived += session_InvitationReplyReceived;
            }
         }
      }
      public override string SessionTypeTag
      {
         get
         {
            return "Chat";
         }
      }
      public override string SessionFullTypeTag
      {
         get
         {
            switch (SessionSubtype)
            {
               case SessionSubtype.Personal: return Resources.S_Personal_chat;
               case SessionSubtype.Translation: return Resources.S_Message_distribution;
               default: return Resources.S_Chat_conference;
            }
         }
      }
      public override string SessionInvitationText
      {
         set
         {
            switch (SessionSubtype)
            {
               case SessionSubtype.Personal:
                  base.SessionInvitationText = value == null ? "" : value;
                  break;
               case SessionSubtype.Conference:
                  base.SessionInvitationText = value == null ? Resources.S_I_invite_you_to_join_to_my_chat : value;
                  break;
               case SessionSubtype.Translation:
                  base.SessionInvitationText = value == null ? Resources.S_I_propose_you_to_view_my_messages : value;
                  break;
            }
         }
      }

      public event EventHandler HistoryPageChanged;

      #endregion

      #region Members

      private void CreateHistoryCache()
      {
         FHistoryCache = new XElement[HistoryFilesCount + 1];

         DelayedAction.Do(FHistoryCache, () => // Clear this cache in 3 min
         {
            for (int i = 0; i < FHistoryCache.Length; i++) FHistoryCache.SetValue(null, i);
            FHistoryCache = null;
         },
         180 * 1000, false);
      }
      private XElement LoadAllHistory()
      {
         if (FHistoryCache == null) CreateHistoryCache();

         string xml = Session.IsPersonal ?
                      FCommunicator.EventLog.Load(Session.Interlocutor, DateTime.MinValue, DateTime.MaxValue) :
                      FCommunicator.EventLog.Load(Session as MediaSession, 0);

         return xml == null ? null : FHistoryCache[HistoryFilesCount] = XElement.Parse(xml);
      }
      private void ApplyTextFilter(string s)
      {
         XElement xLog = GetHistoryFromCache(HistoryFilesCount) ?? LoadAllHistory();

         if (xLog == null) return;

         IEnumerable<XElement> xFiltered = FilterText(xLog, s);

         if (xFiltered.Count() > 0)
         {
            LiteHtml = true;

            ShowLog(xFiltered, 0);
         }
         else
         {
            MessageBox.Show(Resources.S_String_was_not_found.Replace("<s>", s));
         }
      }
      private string PrepareHtml(string text)
      {
         text = Regex.Replace(text, "[^\\s]{50,}", new MatchEvaluator((m) =>
         {
            return "<span .wrap>" + m + "</span>";
         }));
         if (!LiteHtml)
         {
            text = Regex.Replace(text, TextSvc.UrlPattern, new MatchEvaluator((m) =>
            {
               FUrlBuf.Add(m.Value);
               return FUrlStub;
            }),
            RegexOptions.IgnoreCase);

            if (!string.IsNullOrEmpty(InternetCommunicator.Self.EmoPack.RegexPattern))
            {
               text = Regex.Replace(text, InternetCommunicator.Self.EmoPack.RegexPattern, new MatchEvaluator((m) =>
               {
                  return InternetCommunicator.Self.EmoPack.GetEmoHtml(InternetCommunicator.Self.EmoPack[m.Value], true);
               }),
               RegexOptions.IgnoreCase);
            }

            int i = 0;
            text = Regex.Replace(text, FUrlStub, new MatchEvaluator((m) =>
            {
               return FUrlBuf[i++];
            }),
            RegexOptions.IgnoreCase);

            FUrlBuf.Clear();
         }
         return Regex.Replace(text, TextSvc.UrlPattern, new MatchEvaluator((m) =>
         {
            return @"<a .url>" + m.Value + "</a>";
         }),
         RegexOptions.IgnoreCase);
      }
      private XElement LoadHistory(int pageIndex)
      {
         if (FHistoryCache == null) CreateHistoryCache();

         string xml = Session.IsPersonal ?
                      FCommunicator.EventLog.Load(Session.Interlocutor, pageIndex) :
                      FCommunicator.EventLog.Load(Session as MediaSession, pageIndex);

         return xml == null ? null : FHistoryCache[pageIndex] = XElement.Parse(xml);
      }
      private bool ApplyContentFilter(TextDataTypes t)
      {
         XElement xLog = GetHistoryFromCache(HistoryFilesCount) ?? LoadAllHistory();

         if (xLog == null) return false;

         IEnumerable<XElement> xFiltered = FilterContent(xLog, t);

         if (xFiltered.Count() > 0)
         {
            LiteHtml = true;

            ShowLog(xFiltered, 0);

            return true;
         }
         else
         {
            MessageBox.Show(Resources.S_Content_was_not_found);

            return false;
         }
      }
      private bool PageContains(string s, int pageIndex)
      {
         if (pageIndex < 0) pageIndex = HistoryFilesCount - 1;

         XElement xLog = GetHistoryFromCache(pageIndex) ?? LoadHistory(pageIndex);

         return xLog == null ? false : FilterText(xLog, s).Count() > 0;
      }
      private XElement GetHistoryFromCache(int pageIndex)
      {
         DelayedAction.Putoff(FHistoryCache, 60 * 1000); // Putoff clearing cache at 1 min

         return (FHistoryCache != null && pageIndex < FHistoryCache.Length) ? FHistoryCache[pageIndex] : null;
      }
      private IEnumerable<XElement> FilterText(XElement xLog, string s)
      {
         return xLog.Elements().Where(x =>
         {
            XElement y = x.Elements("Content").FirstOrDefault();
            return y == null ? false : TextSvc.Contains(y.Value, s);
         });
      }
      private IEnumerable<XElement> FilterContent(XElement xLog, TextDataTypes ct)
      {
         return xLog.Elements().Where(x =>
         {
            XElement y = x.Elements("Content").FirstOrDefault();
            return y == null ? false : TextSvc.Contains(y.Value, ct);
         });
      }
      private bool ShouldAppendToPreviuos(ServiceMessage currMsg, ServiceMessage prevMsg)
      {
         return prevMsg != null && prevMsg.Sender.Identifier == currMsg.Sender.Identifier &&
                        (currMsg.TsLocal.Value - prevMsg.TsLocal.Value).TotalSeconds < 60;
      }
      private string GetMessageHtml(ServiceMessage currMsg, ServiceMessage prevMsg, bool append)
      {
         string html = "";
         string text = PrepareHtml(currMsg.Text);

         if (currMsg is PresenceNotification)
         {
            if (prevMsg != null) html += MessageTemplateParts.Close + "\r\n";

            html += string.Format(FStatusEventTemplate,
                                  currMsg.IsIncoming ? "in" : "out",
                                  currMsg.Sender.CustomName,
                                  currMsg.TsActual.ToString(),
                                  text);

            FMessageToAppendTo = null;
         }
         else if (currMsg is ChatMessage)
         {
            if (append)
            {
               html += string.Format(MessageTemplateParts.Content,
                                     currMsg.TsActual.ToString("T"),
                                     text);

               if (FMessageToAppendTo == null) FMessageToAppendTo = prevMsg;
            }
            else
            {
               if (prevMsg != null) html += MessageTemplateParts.Close + "\r\n";

               DateTime ts = currMsg.TsActual;

               if (LiteHtml)
               {
                  html += string.Format(MessageTemplateParts.Caption,
                                        currMsg.LocalId,
                                        currMsg.IsIncoming ? "in" : "out",
                                        currMsg.Sender.CustomName,
                                        ts.ToString("d MMMM yyyy"));
               }
               else
               {
                  html += string.Format(MessageTemplateParts.Caption,
                                        currMsg.LocalId,
                                        currMsg.IsIncoming ? "in" : "out",
                                        currMsg.Sender.Identifier,
                                        currMsg.Sender.CustomName,
                                        ts.ToString("d MMMM yyyy"));
               }

               html += string.Format(MessageTemplateParts.Content,
                                     ts.ToString("T"),
                                     text);

               FMessageToAppendTo = null;
            }
         }
         return html;
      }

      public override void Visualize()
      {
         if (Session == null) return;
         
         SuspendLayout();
         Parent.SuspendLayout();

         ShowMainPage();
         BringToFront();
         Visible = true;

         Parent.ResumeLayout();
         ResumeLayout();

         Refresh();
      }
      public override void ClearView()
      {
         base.ClearView();
      }
      public override void RefreshView()
      {
         if (FHtmlView != null) FHtmlView.RefreshHtml();

         base.RefreshView();
      }

      public void NextHistoryPage()
      {
         if (HistoryPageIndex < 0)
         {
            ShowHistoryPage(-1, true, false);
         }
         else if (FCurrentPageTrimmed)
         {
            ShowHistoryPage(HistoryPageIndex, true, false);
         }
         else
         {
            ShowHistoryPage(HistoryPageIndex + 1, true, false);
         }
      }
      public void PrevHistoryPage()
      {
         if (HistoryPageIndex < 0)
         {
            ShowHistoryPage(-1, true, false);
         }
         else if (FCurrentPageTrimmed)
         {
            ShowHistoryPage(HistoryPageIndex, true, false);
         }
         else
         {
            ShowHistoryPage(HistoryPageIndex - 1, true, false);
         }
      }
      public void ScrollToEnd(bool smooth)
      {
         if (FHtmlView != null && FHtmlView.HtmlBody != null)
         {
            DelayedAction.Do(FHtmlView, () => FHtmlView.HtmlBody.ScrollToEnd(smooth), 50, true);
         }
      }
      public void FindText(string s, bool fwd)
      {
         if (s == "")
         {
            ShowHistoryPage(-1, false, true);
            return;
         }
         if (FilteredSearch)
         {
            if (s != FHtmlView.SearchString) ApplyTextFilter(s);
         }
         else if (PageContains(s, HistoryPageIndex))
         {
            LiteHtml = true;

            if (FCurrentPageTrimmed) ShowHistoryPage(HistoryPageIndex, true, false);
         }
         FHtmlView.FindText(s, "span.text", fwd);
      }
      public void ShowMessage(ServiceMessage message)
      {
         if (FHtmlView != null)
         {
            bool append = ShouldAppendToPreviuos(message, FLastShownMessage);
            string html = GetMessageHtml(message, FLastShownMessage, append);
            HtmlControl hc = append && FMessageToAppendTo != null ? FHtmlView[FMessageToAppendTo.LocalId.ToString()] : FHtmlView["log"];

            if (hc != null)
            {
               Element img = hc.HtmlElement.AddHtml(html, false).Select("img");

               if (img != null)
               {
                  if (FLastImgElement != null) FLastImgElement.set_attribute("id", "");

                  FLastImgElement = img;
                  FLastImgElement.set_attribute("id", "last_emo");
               }

               ScrollToEnd(true);
               FLastShownMessage = message is ChatMessage ? message : null;
            }
         }
      }
      public void ShowHistoryPage(int index, bool full, bool scroll)
      {
         FShowStatusEvents = false;

         if (index < 0)
         {
            FHistoryPageIndex = HistoryFilesCount - 1;

            LiteHtml = false;
            FilteredSearch = false;
            FContentFilter = TextDataTypes.None;

            XElement xLog = LoadHistory(FHistoryPageIndex);

            ShowLog(xLog == null ? null : xLog.Elements(), full ? 0 : 30); // DO NOT use cache here - new messages must be shown.
         }
         else
         {
            int count = HistoryFilesCount;

            if (index >= count) index = 0;

            XElement xLog = count > 1 ? (GetHistoryFromCache(index) ?? LoadHistory(index)) : LoadHistory(index);

            if (xLog != null)
            {
               FHistoryPageIndex = index;

               ShowLog(xLog.Elements(), full ? 0 : 30);
            }
         }

         if (scroll) ScrollToEnd(false);
         
         if (HistoryPageChanged != null) HistoryPageChanged(this, EventArgs.Empty);
      }
      internal void ShowLog(IEnumerable<XElement> xLog, int countFromEnd)
      {
         FLastShownMessage = null;
         FMessageToAppendTo = null;
         
         if (FHtmlView == null)
         {
            FHtmlView = new HtmlView();
            panelMainPage.Controls.Add(FHtmlView);
            FHtmlView.FindTextFinished += htmlView_FindTextFinished;
            FHtmlView.HtmlControlEvent += new EventHandler<HtmlControlEventArgs>(htmlView_HtmlControlEvent);
         }
         if (xLog == null || xLog.Count() == 0)
         {
            FHtmlView.LoadHtml(string.Format(Resources.LogBlank, LogStyle, Resources.T_HtmlMenu, InternetCommunicator.Self.EmoPack.GetEmoPopupHtml()), "");
         }
         else
         {
            int logCount = xLog.Count();
            int skipCount = countFromEnd > 0 && logCount > countFromEnd ? logCount - countFromEnd : 0;
            int count = logCount - skipCount;

            FCurrentPageTrimmed = skipCount > 0;

            if (skipCount > 0) xLog = xLog.Skip(skipCount);

            StringBuilder html = new StringBuilder(2048 + count * 80 /* avg length of data */);

            html.AppendFormat(Resources.LogBlank, LogStyle, Resources.T_HtmlMenu, InternetCommunicator.Self.EmoPack.GetEmoPopupHtml());

            XElement[] xArr = xLog.ToArray(); // cycle is very slow without this

            for (int i = 0; i < count; i++)
            {
               ServiceMessage currMsg = ServiceMessage.Create(xArr[i]);
               ServiceMessage prevMsg = i > 0 ? ServiceMessage.Create(xArr[i - 1]) as ChatMessage : null;

               FCommunicator.NormalizeMessage(currMsg);

               html.Append(GetMessageHtml(currMsg, prevMsg, ShouldAppendToPreviuos(currMsg, prevMsg)));
            }
            FHtmlView.LoadHtml(html.ToString(), "");
         }
         FCommunicator.OptimizeMemorySize();
      }

      public bool FilteredSearch
      {
         get;
         set;
      }
      public TextDataTypes ContentFilter
      {
         get
         {
            return FContentFilter;
         }
         set
         {
            if (value == FContentFilter) return;

            if (value == TextDataTypes.None)
            {
               ShowHistoryPage(-1, false, true);

               FContentFilter = TextDataTypes.None;
            }
            else if (ApplyContentFilter(value))
            {
               FContentFilter = value;
            }
         }
      }

      #endregion

      #region Handlers

      private void htmlView_HtmlControlEvent(object sender, HtmlControlEventArgs e)
      {
         // {e.Target.HtmlTag}, {e.Target.Value}, {e.EventType}
         if (e.EventType == BehaviorEvents.BE_CONTEXT_MENU_REQUEST)
         {
            if (string.IsNullOrEmpty(e.Target.Class))
            {
               if (e.Target.HtmlTag == "body") MenuWrapper.ShowMenu(InternetCommunicator.Self.Components.menuHistory);
            }
            else
            {
               if (e.Target.Class == "refl") MenuWrapper.ShowMenu(InternetCommunicator.Self.Components.menuHistory);
            }
         }
         else if (e.EventType == BehaviorEvents.BE_BUTTON_CLICK)
         {
            if (e.Target["user"] != null)
            {
               Contact contact = Session.Account.GetContact(e.Target["user"]);
               if (contact != null) InternetCommunicator.Self.ShowUserProperties(contact, "");
            }
         }
         else if (e.EventType == BehaviorEvents.BE_MENU_ITEM_CLICK)
         {
            if (e.Target.Id == "itemCopyUrl")
            {
               if (FHtmlView.Tag is string) Clipboard.SetText(FHtmlView.Tag.ToString());
            }
            else if (e.Target.Id == "itemOpenUrl")
            {
               if (FHtmlView.Tag is string) Shell.OpenLink(FHtmlView.Tag.ToString());
            }
         }
         else if ((int)e.EventType == 65551)
         {
            FHtmlView.Tag = e.Target.Text;
         }
      }
      private void htmlView_FindTextFinished(object sender, FindTextFinishedEventArgs e)
      {
         if (FilteredSearch) return;

         LiteHtml = true;

         int showIndex = HistoryPageIndex;
         int nextIndex = HistoryPageIndex;
         int filesCount = HistoryFilesCount;

         if (e.Forward)
         {
            for (int i = 0; i < filesCount; i++)
            {
               if (++nextIndex < filesCount)
               {
                  if (PageContains(e.SearchString, nextIndex))
                  {
                     showIndex = nextIndex;
                     break;
                  }
               }
               else
               {
                  nextIndex = -1;
               }
            }
         }
         else
         {
            for (int i = 0; i < filesCount; i++)
            {
               if (--nextIndex >= 0)
               {
                  if (PageContains(e.SearchString, nextIndex))
                  {
                     showIndex = nextIndex;
                     break;
                  }
               }
               else
               {
                  nextIndex = filesCount;
               }
            }
         }
         if (showIndex != HistoryPageIndex)
         {
            DelayedAction.Do(() =>
            {
               HistoryPageIndex = showIndex;
               FindText(e.SearchString, e.Forward);
            },
            10);
         }
      }
      private void settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
      {
         if (e.PropertyName == "SelectedLogStyleName") FHtmlView.Css = FCommunicator.SelectedLogStyle;
         else if (e.PropertyName == "CustomLogStyle") FHtmlView.Css = Settings.Default.CustomLogStyle;
         else if (e.PropertyName == "SelectedMessageTemplateName") FSelectedMessageTemplateParts.Parse(FCommunicator.SelectedMessageTemplate);
      }
      private void session_ParamsChanged(object sender, PropertyChangedEventArgs e)
      {
         if (!Session.LogEvents) return;

         if (e.PropertyName == "Subject")
         {
            //
         }
      }
      private void session_PresenceNotified(object sender, MessagingOperationEventArgs e)
      {
         if (!Session.LogEvents) return;

         ShowMessage(e.EventMessage);
      }
      private void session_SendMessageState(object sender, MessagingOperationEventArgs e)
      {
         if (e.Error != null)
         {
            //ShowMessage(e.EventMessage);
            //ShowMessageError(e.EventMessage, e.Error);
         }
         else if (e.State == OperationState.DataSending)
         {
            ShowMessage(e.EventMessage);
         }
         else if (e.State == OperationState.DataSent)
         {
            //UpdateMessage(e.EventMessage, null, MessageUpdateOptions.LocalTimestamp);
         }
         else if (e.State == OperationState.Callback)
         {
            //UpdateMessage(e.RequestMessage, e.ReplyMessage.Data, MessageUpdateOptions.ServerInTimestamp);
         }
      }
      private void session_InvitationReceived(object sender, MessagingOperationEventArgs e)
      {
         if (!Session.LogEvents) return;

         ShowMessage(e.EventMessage);
      }
      private void session_ChatMessageReceived(object sender, MessagingOperationEventArgs e)
      {
         if (!Session.LogEvents) return;

         if (e.EventMessage.Action == ServiceActions.TXTMSG) ShowMessage(e.EventMessage);
      }
      private void session_AcknowledgeReceived(object sender, MessagingOperationEventArgs e)
      {
         if (!Session.LogEvents) return;

         if (e.Error != null && e.RequestMessage != null)
         {
            //
         }
      }
      private void session_ParticipantsChanged(object sender, ParticipantsChangedEventArgs e)
      {
         if (!e.Show) return;
      }
      private void session_MessageUpdateReceived(object sender, MessagingOperationEventArgs e)
      {
         //
      }
      private void session_InvitationReplyReceived(object sender, MessagingOperationEventArgs e)
      {
         //
      }

      #endregion
   }

   public class ChatSession : MediaSession
   {
      public ChatSession(Account account, User owner, IEnumerable<User> users, ServiceSession hostingSession, SessionVisibility visibility, SessionSubtype subtype)
         : base(account, owner, users, hostingSession, visibility, subtype)
      {
         InitializeMedia();
      }

      public ChatSession(Account account, XElement xData, IEnumerable<User> users)
         : base(account, xData, users)
      {
         InitializeMedia();
      }

      public override void CleanupMedia()
      {
         ChatControl.Session = null;
         ChatControl.ClearView();
         base.CleanupMedia();
      }
      public override void InitializeMedia()
      {
         if (FVisualizer != null) return;

         FVisualizer = new ChatControl(FCommunicator, this);
         (FVisualizer as ChatControl).Dock = DockStyle.Fill;
      }

      public ChatControl ChatControl
      {
         get
         {
            return FVisualizer as ChatControl;
         }
      }
      public override string Caption
      {
         get
         {
            string typeTag = "";
            string names = RecipientsNames;
            if (names.Length == 0) names = "No Recipients";
            string subject = string.IsNullOrEmpty(FSubject) ? "" : FSubject + " - ";
            switch (FSubtype)
            {
               case SessionSubtype.Personal: typeTag = " - " + Resources.S_Personal_chat; break;
               case SessionSubtype.Conference: typeTag = " - " + Resources.S_Chat_conference; break;
               case SessionSubtype.Translation: typeTag = " - " + Resources.S_Multicast_message_session; break;
            }
            return subject + names + typeTag;
         }
      }

      public void Show(bool history)
      {
         if (history)
         {
            ChatControl.ShowHistoryPage(-1, false, true);
         }
         else
         {
            ChatControl.ShowLog(null, 0);
         }
      }
   }

   internal class MessageTemplateParts
   {
      string[] parts = null;

      internal MessageTemplateParts(string t)
      {
         Parse(t);
      }
      internal void Parse(string t)
      {
         if (parts == null) parts = new string[3];

         parts[0] = t.SubstrAfter("[CAPTION]").SubstrBefore("[CONTENT]").Trim();
         parts[1] = t.SubstrAfter("[CONTENT]").SubstrBefore("[CLOSE]").Trim();
         parts[2] = t.SubstrAfter("[CLOSE]").Trim();
      }

      internal string Caption
      {
         get
         {
            return parts[0];
         }
      }
      internal string Content
      {
         get
         {
            return parts[1];
         }
      }
      internal string Close
      {
         get
         {
            return parts[2];
         }
      }
   }
}